package com.ruoyi.business.service.s7;

import com.ruoyi.business.domain.S7VariablesConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.PreDestroy;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

/**
 * S7连接池管理器
 * 简化版连接池实现
 *
 * @author qiancheng
 * @date 2025-09-02
 */
@Service
public class S7ConnectionPoolManager {
    private static final Logger log = LoggerFactory.getLogger(S7ConnectionPoolManager.class);

    // 连接池配置
    private static final int MIN_CONNECTIONS_PER_PLC = 1;
    private static final int MAX_CONNECTIONS_PER_PLC = 3;
    
    // 数据获取间隔（秒）
    public static final long DATA_ACQUISITION_INTERVAL = 5;

    // 连接池和相关信息
    private final Map<String, BlockingQueue<S7Client>> connectionPools = new ConcurrentHashMap<>();
    private final Map<String, ConnectionInfo> connectionInfos = new ConcurrentHashMap<>();
    private final Map<String, Boolean> connectionStatus = new ConcurrentHashMap<>();
    private final Map<String, AtomicLong> connectionUsageCount = new ConcurrentHashMap<>();
    private final Map<String, AtomicLong> readSuccessCount = new ConcurrentHashMap<>();
    private final Map<String, AtomicLong> readFailureCount = new ConcurrentHashMap<>();

    private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);

    // 连接信息类
    private static class ConnectionInfo {
        final String host;
        final int port;
        final int rack;
        final int slot;

        ConnectionInfo(String host, int port, int rack, int slot) {
            this.host = host;
            this.port = port;
            this.rack = rack;
            this.slot = slot;
        }
    }

    /**
     * 初始化指定PLC的连接池
     */
    public CompletableFuture<Boolean> initializeConnectionPool(String plcIp, List<S7VariablesConfig> variables) {
        if (variables == null || variables.isEmpty()) {
            log.warn("PLC [{}] 没有配置变量，跳过连接池初始化", plcIp);
            return CompletableFuture.completedFuture(false);
        }

        S7VariablesConfig config = variables.get(0);
        int rack = config.getRack() != null ? config.getRack().intValue() : 0;
        int slot = config.getSlot() != null ? config.getSlot().intValue() : 1;
        int port = config.getPlcPort() != null ? config.getPlcPort().intValue() : 102;

        // 保存连接信息
        connectionInfos.put(plcIp, new ConnectionInfo(plcIp, port, rack, slot));

        // 创建连接池
        BlockingQueue<S7Client> pool = new ArrayBlockingQueue<>(MAX_CONNECTIONS_PER_PLC);
        connectionPools.put(plcIp, pool);

        // 初始化监控计数器
        connectionUsageCount.put(plcIp, new AtomicLong(0));
        readSuccessCount.put(plcIp, new AtomicLong(0));
        readFailureCount.put(plcIp, new AtomicLong(0));

        // 创建初始连接
        return createInitialConnections(plcIp, pool, MIN_CONNECTIONS_PER_PLC)
                .thenApply(successCount -> {
                    if (successCount > 0) {
                        connectionStatus.put(plcIp, true);
                        log.info("PLC [{}] 连接池初始化成功，初始连接数: {}/{}", plcIp, successCount, MIN_CONNECTIONS_PER_PLC);
                        // 启动连接健康检查
                        startHealthCheck(plcIp);
                        return true;
                    } else {
                        connectionStatus.put(plcIp, false);
                        log.error("PLC [{}] 连接池初始化失败", plcIp);
                        return false;
                    }
                });
    }

    /**
     * 创建初始连接
     */
    private CompletableFuture<Integer> createInitialConnections(String plcIp, BlockingQueue<S7Client> pool, int count) {
        ConnectionInfo info = connectionInfos.get(plcIp);
        if (info == null) {
            return CompletableFuture.completedFuture(0);
        }

        List<CompletableFuture<Boolean>> connectionFutures = new ArrayList<>();
        
        for (int i = 0; i < count; i++) {
            S7Client client = new S7Client(info.host, info.port, info.rack, info.slot);
            CompletableFuture<Boolean> connectFuture = client.connect()
                    .thenApply(success -> {
                        if (success) {
                            pool.offer(client);
                            return true;
                        } else {
                            client.disconnect();
                            return false;
                        }
                    });
            connectionFutures.add(connectFuture);
        }

        return CompletableFuture.allOf(connectionFutures.toArray(new CompletableFuture[0]))
                .thenApply(v -> {
                    int successCount = 0;
                    for (CompletableFuture<Boolean> future : connectionFutures) {
                        try {
                            if (future.get()) {
                                successCount++;
                            }
                        } catch (Exception e) {
                            log.error("检查连接创建结果时发生异常", e);
                        }
                    }
                    return successCount;
                });
    }

    /**
     * 从连接池获取连接
     */
    public CompletableFuture<S7Client> borrowConnection(String plcIp) {
        connectionUsageCount.get(plcIp).incrementAndGet();
        
        BlockingQueue<S7Client> pool = connectionPools.get(plcIp);
        if (pool == null) {
            CompletableFuture<S7Client> future = new CompletableFuture<>();
            future.completeExceptionally(new IllegalStateException("PLC [" + plcIp + "] 连接池不存在"));
            return future;
        }

        // 尝试从连接池获取连接
        S7Client client = pool.poll();
        if (client != null && client.isConnected()) {
            return CompletableFuture.completedFuture(client);
        }
        
        // 如果连接不可用，关闭并重新创建
        if (client != null) {
            client.disconnect();
        }

        // 创建新连接
        ConnectionInfo info = connectionInfos.get(plcIp);
        if (info != null && pool.size() < MAX_CONNECTIONS_PER_PLC) {
            S7Client newClient = new S7Client(info.host, info.port, info.rack, info.slot);
            return newClient.connect().thenApply(success -> {
                if (success) {
                    return newClient;
                } else {
                    newClient.disconnect();
                    throw new RuntimeException("创建新连接失败");
                }
            });
        }

        CompletableFuture<S7Client> future = new CompletableFuture<>();
        future.completeExceptionally(new RuntimeException("无法获取连接"));
        return future;
    }

    /**
     * 归还连接到连接池
     */
    public void returnConnection(String plcIp, S7Client client) {
        if (client == null) {
            return;
        }

        BlockingQueue<S7Client> pool = connectionPools.get(plcIp);
        if (pool != null) {
            // 检查连接是否仍然有效
            if (client.isConnected()) {
                // 检查连接池是否还有空间
                if (pool.size() < MAX_CONNECTIONS_PER_PLC) {
                    if (!pool.offer(client)) {
                        // 连接池已满，关闭连接
                        client.disconnect();
                    }
                } else {
                    // 连接池超出最大限制，关闭连接
                    client.disconnect();
                }
            } else {
                // 连接已断开，直接关闭
                client.disconnect();
            }
        } else {
            // 连接池不存在，关闭连接
            client.disconnect();
        }
    }

    /**
     * 启动连接健康检查
     */
    private void startHealthCheck(String plcIp) {
        scheduler.scheduleWithFixedDelay(() -> {
            try {
                healthCheckForPLC(plcIp);
            } catch (Exception e) {
                log.error("PLC [{}] 健康检查异常", plcIp, e);
            }
        }, 60, 60, TimeUnit.SECONDS);
    }

    /**
     * 对指定PLC执行健康检查
     */
    private void healthCheckForPLC(String plcIp) {
        BlockingQueue<S7Client> pool = connectionPools.get(plcIp);
        if (pool == null) {
            return;
        }
        
        List<S7Client> checkedClients = new ArrayList<>();
        S7Client client;
        int removedCount = 0;
        
        // 检查连接池中的所有连接
        while ((client = pool.poll()) != null) {
            if (client.isConnected()) {
                checkedClients.add(client);
            } else {
                client.disconnect();
                removedCount++;
            }
        }

        // 将有效连接放回连接池
        for (S7Client validClient : checkedClients) {
            pool.offer(validClient);
        }

        // 确保连接数
        int currentConnections = checkedClients.size();
        if (currentConnections < MIN_CONNECTIONS_PER_PLC) {
            int needed = MIN_CONNECTIONS_PER_PLC - currentConnections;
            createInitialConnections(plcIp, pool, needed);
        }

        // 更新连接状态
        boolean hasConnections = !checkedClients.isEmpty();
        connectionStatus.put(plcIp, hasConnections);
        
        // 记录监控信息
        long usageCount = connectionUsageCount.get(plcIp).get();
        long successCount = readSuccessCount.get(plcIp).get();
        long failureCount = readFailureCount.get(plcIp).get();
        log.debug("PLC [{}] 监控信息 - 连接使用次数: {}, 读取成功: {}, 读取失败: {}", 
                plcIp, usageCount, successCount, failureCount);
    }

    /**
     * 获取连接状态
     */
    public boolean isConnected(String plcIp) {
        return connectionStatus.getOrDefault(plcIp, false);
    }

    /**
     * 记录读取成功
     */
    public void recordReadSuccess(String plcIp) {
        AtomicLong counter = readSuccessCount.get(plcIp);
        if (counter != null) {
            counter.incrementAndGet();
        }
    }

    /**
     * 记录读取失败
     */
    public void recordReadFailure(String plcIp) {
        AtomicLong counter = readFailureCount.get(plcIp);
        if (counter != null) {
            counter.incrementAndGet();
        }
    }

    /**
     * 获取PLC监控信息
     */
    public Map<String, Object> getPlcMonitoringInfo(String plcIp) {
        Map<String, Object> info = new HashMap<>();
        info.put("connected", isConnected(plcIp));
        info.put("usageCount", connectionUsageCount.get(plcIp).get());
        info.put("readSuccessCount", readSuccessCount.get(plcIp).get());
        info.put("readFailureCount", readFailureCount.get(plcIp).get());
        return info;
    }

    /**
     * 销毁资源
     */
    @PreDestroy
    public void destroy() {
        log.info("正在关闭S7连接池管理器...");
        
        // 关闭调度器
        scheduler.shutdown();
        
        // 关闭所有连接池中的连接
        for (Map.Entry<String, BlockingQueue<S7Client>> entry : connectionPools.entrySet()) {
            String plcIp = entry.getKey();
            BlockingQueue<S7Client> pool = entry.getValue();
            
            S7Client client;
            while ((client = pool.poll()) != null) {
                try {
                    client.disconnect();
                } catch (Exception e) {
                    log.error("关闭PLC [{}] 连接时发生异常", plcIp, e);
                }
            }
        }
        
        connectionPools.clear();
        connectionInfos.clear();
        connectionStatus.clear();
        connectionUsageCount.clear();
        readSuccessCount.clear();
        readFailureCount.clear();
        
        log.info("S7连接池管理器已关闭");
    }
}